#!/usr/bin/env node

const fs = require('fs');
const https = require('https');
const path = require('path');
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
const axios = require('axios');

const base = path.resolve(__dirname, '..');
const shell = path.resolve(base, 'shell');

const har = require(`${ shell }/server/har-file`);

console.log(path.resolve(shell, 'server.key'));

const options = {
  key:  fs.readFileSync(path.resolve(shell, 'server', 'server.key')),
  cert: fs.readFileSync(path.resolve(shell, 'server', 'server.crt'))
};

let PORT = process.env.PORT || '8005';

PORT = parseInt(PORT, 10);

if (isNaN(PORT)) {
  console.log('Invalid port'); // eslint-disable-line no-console
  process.exit(1);
}

// Need at least two arguments

if (process.argv.length < 4) {
  console.log('Requires 2 arguments. Can also take an optional folder:');
  console.log('  <har_file>  path to HAR file to load');
  console.log('  <version>   dashboard version number to use for static assets (e.g v2.8.0, latest)');
  console.log('  [<folder>]  folder containing json files to use as a fallback when HAR file does not contain request');
  console.log('');

  process.exit(1);
}

const harFile = process.argv[2];
const version = process.argv[3].trim();
const harData = har.loadFile(harFile, PORT, '/dashboard');
const dashboardUrl = `https://releases.rancher.com/dashboard/${ version }/index.html`;

const harFolder = process.argv.length > 4 ? process.argv[4] : '';

console.log(dashboardUrl);

const dev = (process.env.NODE_ENV !== 'production');
const devPorts = dev || process.env.DEV_PORTS === 'true';

const app = express();

// Catch reload on a dynamic page
// Check that the requestor will accept html and send them the index file
app.use('*', async(req, res, next) => {
  const accept = req.headers.accept || '';
  const acceptArray = accept.split(',');
  const html = acceptArray.find((h) => h.trim() === 'text/html');

  if (html) {
    try {
      const response = await axios.get(dashboardUrl, { responseType: 'arraybuffer' });

      res.type('text/html');
      res.status(response.status);
      res.send(response.data);
    } catch (error) {
      console.error('Error fetching dashboard URL:', error);
      res.status(500).send('Error fetching dashboard URL');
    }

    return;
  }

  next();
});

app.use('/dashboard', createProxyMiddleware(proxyWsOpts(dashboardUrl)));

// Add in handler for har file requests
app.use(har.harProxy(harData, harFolder));

const server = https.createServer(options, app);
const appServer = server.listen(PORT);

console.log(`Running Dashboard web server on port ${ PORT }`); // eslint-disable-line no-console

appServer.on('upgrade', (req, socket, head) => {
  const responseHeaders = ['HTTP/1.1 101 Web Socket Protocol Handshake', 'Upgrade: WebSocket', 'Connection: Upgrade'];

  socket.write(`${ responseHeaders.join('\r\n') }\r\n\r\n`);
});

// ===============================================================================================
// Functions for the request proxying used in dev
// ===============================================================================================

function proxyOpts(target) {
  return {
    target,
    secure:       !devPorts,
    ws:           false,
    changeOrigin: true,
    onProxyReq,
    onProxyReqWs,
    onError,
    onProxyRes,
  };
}

function onProxyRes(proxyRes, req, res) {
  if (devPorts) {
    proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
  }
}

function proxyWsOpts(target) {
  return {
    ...proxyOpts(target),
    ws:           false,
    changeOrigin: true,
    secure:       false,
  };
}

function onProxyReq(proxyReq, req) {
  if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
    proxyReq.setHeader('x-api-host', req.headers['host']);
    proxyReq.setHeader('x-forwarded-proto', 'https');
    // console.log(proxyReq.getHeaders());
  }
}

function onProxyReqWs(proxyReq, req, socket, options, head) {
  req.headers.origin = options.target.href;
  proxyReq.setHeader('origin', `${ options.target.href }/`);
  proxyReq.setHeader('x-api-host', req.headers['host']);
  proxyReq.setHeader('x-forwarded-proto', 'https');

  socket.on('error', (err) => {
    console.error('Proxy WS Error:', err); // eslint-disable-line no-console
  });
}

function onError(err, req, res) {
  res.statusCode = 598;
  console.error('Proxy Error:', err); // eslint-disable-line no-console
  res.write(JSON.stringify(err));
}
